package net.neocat.tcx.util;

import com.google.common.base.Function;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.annotation.Nullable;
import java.util.Iterator;

/**
 * Created with IntelliJ IDEA.
 * User: jschek
 * Date: 4/25/13
 * Time: 12:01 AM
 * To change this template use File | Settings | File Templates.
 */
public abstract class DomUtils {

    public static boolean isNullOrEmpty(NodeList nodeList) {
        return nodeList==null || nodeList.getLength()==0;
    }

    public static Element appendElement(Element parent, String name) {
        Element child = parent.getOwnerDocument().createElement(name);
        parent.appendChild(child);
        return child;
    }

    public static Element appendElement(Element parent, String name, Object value) {
        Element child = appendElement(parent,name);
        child.setTextContent(value.toString());
        return parent;
    }

    public static String getFirstMatchingChildText(Element parent, String childElementName) {
        Element childElement = getFirstMatchingChild(parent,childElementName);
        if(childElement!=null) {
            return childElement.getTextContent();
        }
        return null;
    }

    public static <TNode extends Node> TNode getFirstMatchingChild(Element parent, String childElementName) {
        NodeList children = parent.getElementsByTagName(childElementName);
        if(children==null || children.getLength()==0) {
            return null;
        }
        return (TNode)children.item(0);
    }

    public static Iterable<Node> iterateChildren(Node node) {
        return iterateNodeList(node.getChildNodes());
    }

    public static Iterable<Node> getElementsByName(Element node, String searchName) {
        return iterateNodeList(node.getElementsByTagName(searchName));
    }

    public static Iterable<Node> iterateNodeList(NodeList nodeList) {
        if(nodeList==null || nodeList.getLength()==0) {
            return ImmutableList.<Node>of();
        }
        return new NodeListIterable(nodeList);
    }

    public static Iterable<Element> asElements(Iterable<Node> nodes) {
         return Iterables.transform(nodes, new Function<Node, Element>() {
             @Override
             public Element apply(Node input) {
                return (Element)input;
             }
         });
    }

    private static class NodeListIterable implements Iterable<Node> {
        private final NodeList nodeList;

        private NodeListIterable(NodeList nodeList) {
            this.nodeList = nodeList;
        }

        @Override
        public Iterator<Node> iterator() {
            return new NodeListIterator(nodeList);
        }
    }

    private static class NodeListIterator extends AbstractIterator<Node> {
        private final NodeList nodeList;
        private transient int index;

        private NodeListIterator(NodeList nodeList) {
            this.nodeList = nodeList;
        }

        @Override
        protected Node computeNext() {
            while(index<nodeList.getLength()) {
                Node node = nodeList.item(index);
                index++;
                if(node.getNodeType() == Node.ELEMENT_NODE) {
                    return node;
                }
            }
            return endOfData();
        }
    }
}
